# -*- coding: utf-8 -*-

import time
import json
import datetime

from flask_wtf import Form
from wtforms import (
    StringField, IntegerField, FloatField, BooleanField, DateTimeField,
    SelectField, DateField,
    ValidationError)
from wtforms.fields.html5 import URLField, EmailField
from wtforms.validators import DataRequired, Email, Length, NumberRange, Regexp

from app.models import UserPlan


class HotelDirectBookForm(Form):
    """
    酒店信息检索(录入)页表单 (直接预定)
    """
    checkin_date = DateField(format='%Y-%m-%d', validators=[DataRequired()])  # 必须提供, 页面内不可变
    checkout_date = DateField(format='%Y-%m-%d', validators=[DataRequired()])  # 必须提供, 页面内不可变
    rooms_count = IntegerField(validators=[DataRequired(), NumberRange(min=1)])  # 必须提供, 页面内不可变
    product_id = StringField(validators=[Length(0, 50)])  # 房型id, 提供时页面过滤出指定的房型显示

    def validate_checkin_date(self, field):
        checkin_date = field.data
        if checkin_date and checkin_date < datetime.date.today():
            raise ValidationError(u'入住日期不能早于今天')

    def validate_checkout_date(self, field):
        delta = field.data - self.checkin_date.data
        if delta <= datetime.timedelta(days=0):
            raise ValidationError(u'退房日期必须晚于入住日期')
        if delta > datetime.timedelta(days=30):
            raise ValidationError(u'入住时间不能超过30天')


class HotelOrderForm(Form):
    """
    酒店预订表单
    """
    # 区分采用哪种模式提交
    mode = IntegerField(validators=[DataRequired()])

    # 支持匿名(user.id=None)下订单，匿名情况下用device_id
    user_id = IntegerField()
    device_id = StringField()

    plan_id = IntegerField()
    hotel_id = StringField(validators=[DataRequired(), Length(0, 50)])
    product_id = StringField(validators=[DataRequired(), Length(0, 50)])
    hotel_name = StringField(validators=[DataRequired(), Length(0, 200)])
    product_name = StringField(validators=[DataRequired(), Length(0, 200)])
    hotel_country = StringField(validators=[Length(0, 200)])
    hotel_city = StringField(validators=[Length(0, 200)])

    checkin_date = DateField(format='%Y-%m-%d', validators=[DataRequired()])
    checkout_date = DateField(format='%Y-%m-%d', validators=[DataRequired()])
    contact_mobile = StringField(validators=[Regexp(r'^1[0-9]{10}$|^86[0-9]{11}$|^852[0-9]{8}$|^853[0-9]{8}$|^886[0-9]{9}$'), DataRequired()])
    contact_email = EmailField(validators=[DataRequired()])
    rooms = StringField(validators=[DataRequired()])
    customer_preferences = StringField()
    arrive_hotel_time = DateTimeField(format='%H:%M')
    invoice_title = StringField()

    def validate_mode(self, field):
        if field.data not in [1, 2, 3]:
            raise ValidationError(u'订单模式(mode)错误')

    def validate_plan_id(self, field):
        """
        对于酒店订单页的3种提交模式, plan_id 都需要POST
        在 1 情况下, 对 plan_id 做校验
        在 2 3 情况下, plan_id == None, 直接返回
        """
        plan_id = field.data
        if plan_id:
            try:
                UserPlan.objects.get(pk=plan_id)
            except Exception:
                raise ValidationError(u'行程参数(plan_id)错误')

    def validate_rooms(self, field):
        rooms_json = field.data
        rooms_list = json.loads(rooms_json)
        if not isinstance(rooms_list, list):
            raise ValidationError(u'房间信息格式错误')
        for room in rooms_list:
            if not isinstance(room, dict):
                raise ValidationError(u'房间信息格式错误')
            keys = room.keys()
            if 'firstName' not in keys or \
               'lastName' not in keys or \
               'bedTypeId' not in keys or \
               'adultNum' not in keys or \
               'childAges' not in keys:
                raise ValidationError(u'预订房间信息不全')
            if not room['firstName'] or not room['lastName']:
                raise ValidationError(u'预订房间联系人信息缺失')
            # API 端问题:
            # bedTypeId 有时会返回 bedTypeName (供应商的差异导致)
            # 去掉对 bedTypeId 的验证逻辑, API 端支持将 name 当成 id 提交
            # if not isinstance(room['bedTypeId'], int):
            #     raise forms.ValidationError('bedTypeId should be int')
            if not isinstance(room['adultNum'], int) or room['adultNum'] < 1:
                raise ValidationError(u'成人数量参数错误')
            if room['childAges']:
                for age in room['childAges'].split(','):
                    if not age.isdigit():
                        raise ValidationError(u'入住儿童信息错误')

    def validate_customer_preferences(self, field):
        preferences = field.data
        if preferences:
            # 多选: 1高层房间 2吸烟房 3无烟房
            # 2 和 3 只能选择一个
            for prefer in preferences.split(','):
                if not prefer.isdigit() or prefer not in ['1', '2', '3']:
                    raise ValidationError(u'客户偏好参数错误')
            if '2' in preferences.split(',') and '3' in preferences.split(','):
                raise ValidationError(u'吸烟房和无烟房只能选择一种')

    def validate_user_id(self, field):
        user_id = field.data
        device_id = self.device_id.data
        if not user_id and not device_id:
            raise ValidationError(u'用户标识缺失, 请使用已注册的账号登录, 或使用移动设备提交订单')
        self._identity = user_id or 'DEVICE_' + device_id


class HotelDateAPIForm(Form):
    """
    给日历插件使用的 ajax 接口表单
    """
    type = StringField(validators=[DataRequired(), Length(0, 20)])
    checkin_date = DateField(format='%Y-%m-%d', validators=[DataRequired()])
    checkout_date = DateField(format='%Y-%m-%d', validators=[DataRequired()])
    start = IntegerField(validators=[DataRequired()])
    end = IntegerField(validators=[DataRequired()])

    def validate_type(self, field):
        if field.data not in ['checkin_date', 'checkout_date']:
            raise ValidationError('type error')

    def validate_start(self, field):
        try:
            self._start_date = datetime.date.fromtimestamp(self.start.data)
            self._stop_date = datetime.date.fromtimestamp(self.end.data)
        except:
            raise ValidationError('start or end error ')
